package com.test.web.jdbc.util;

import com.test.web.jdbc.exception.JdbcException;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * com.test.web.jdbc.util
 *
 * @author 白雨浓
 * date: 2018/10/21 13:45
 * content: sql 转换
 */
public class SqlUtil {

    private static final String REG = "#\\{(.+?)\\}";

    public static Result convert(String sql, Map<String, Object> paramMap) {

        Pattern pattern = Pattern.compile(REG);
        Matcher matcher = pattern.matcher(sql);

        List<Object> paramList = new ArrayList<>();

        while (matcher.find()) {
            String param = matcher.group();
            sql = sql.replace(param, "?");

            param = param.substring(2, param.length() - 1);

            paramList.add(paramMap.get(param));
        }

        if (paramMap.size() != paramList.size()) {
            throw new JdbcException("param size mismatching");
        }

        return new Result(sql, paramList);
    }

    /**
     * paramMap优先级高
     */
    public static <T> Result convert(String sql, T target, Map<String, Object> paramMap) {

        Pattern pattern = Pattern.compile(REG);
        Matcher matcher = pattern.matcher(sql);

        List<Object> paramList = new ArrayList<>();

        while (matcher.find()) {
            String param = matcher.group();
            sql = sql.replace(param, "?");

            param = param.substring(2, param.length() - 1);

            Object value;

            if ((value = paramMap.get(param)) != null) {
                paramList.add(value);
                continue;
            }

            if ((value = getValue(target, param)) != null) {
                paramList.add(value);
                continue;
            }

            paramList.add(null);
        }

        return new Result(sql, paramList);
    }

    private static <T> Object getValue(T target, String fieldName) {
        if (target == null) {
            return null;
        }

        try {
            return target.getClass()
                    .getMethod("get" + ColumnUtil.upperCaseFirstOne(fieldName))
                    .invoke(target);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            return null;
        }
    }

    @Data
    @AllArgsConstructor
    public static class Result {

        private String sql;

        private List<Object> paramList;
    }

}
